package com.jd.orm.framework.core.dao.impl;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;
import java.util.List;
import java.util.Map;
import com.jd.orm.framework.core.dialect.Dialect;
import com.jd.orm.framework.core.exception.SystemException;
import com.jd.orm.framework.core.handle.ResultSetHandler;
import com.jd.orm.framework.core.handle.RowListHandler;
import com.jd.orm.framework.core.handle.SingleRowHandler;
import com.jd.orm.framework.core.jdbcwraper.PreparedStatementCreator;
import com.jd.orm.framework.core.mapper.ArrayRowMapper;
import com.jd.orm.framework.core.mapper.BeanRowMapper;
import com.jd.orm.framework.core.mapper.MapRowMapper;
import com.jd.orm.framework.core.mapper.RowMapper;
import com.jd.orm.framework.core.mapper.SingleColumnRowMapper;
import com.jd.orm.framework.core.util.PageResult;
import com.jd.orm.framework.core.util.QueryCriteria;
import com.jd.orm.framework.core.util.SQLUtils;

/**
 * 
 * ClassName: JDConnectOrmTemplate <br/>
 * Function: TODO ADD FUNCTION. <br/>
 * Reason: TODO ADD REASON. <br/>
 * date: 2014-5-13 下午1:52:15 <br/>
 * 
 * @author liubing1@jd.com
 * @version
 * @since up JDK 1.5
 */
public class JdOrmTemplate {
	
	private JdOrmTemplate() {
	}

	private static class JdOrmTemplateHolder {
		static final JdOrmTemplate instance = new JdOrmTemplate();
	}

	public static JdOrmTemplate getInstance() {
		return JdOrmTemplateHolder.instance;
	}
	protected static <T> List<T> queryAsList(Connection conn, RowMapper<T> rowMapper,
			String sql, Object... parameters) {
		// AssertUtils.notNull(rowMapper, "rowMapper is null.");

		ResultSetHandler<List<T>> rsh = new RowListHandler<T>(rowMapper);
		return query(conn, rsh, sql, parameters);
	}

	protected static <T> List<T> queryAsList(Connection conn, Class<T> beanClass,
			String sql, Object... parameters) {
		// AssertUtils.notNull(beanClass, "beanClass is null.");
		RowMapper<T> rowMapper = getRowMapper(beanClass);
		return queryAsList(conn, rowMapper, sql, parameters);
	}

	protected static <T> T queryAsObject(Connection conn, RowMapper<T> rowMapper,
			String sql, Object... parameters) {
		ResultSetHandler<T> rsh = new SingleRowHandler<T>(rowMapper);
		return query(conn, rsh, sql, parameters);
	}

	protected static <T> T queryAsObject(Connection conn, Class<T> beanClass,
			String sql, Object... parameters) {
		// AssertUtils.notNull(beanClass, "beanClass is null.");

		RowMapper<T> rowMapper = getRowMapper(beanClass);
		return queryAsObject(conn, rowMapper, sql, parameters);
	}

	protected static Integer queryAsInt(Connection conn, String sql,
			Object... parameters) {
		return queryAsObject(conn, Integer.class, sql, parameters);
	}

	protected static Long queryAsLong(Connection conn, String sql,
			Object... parameters) {
		return queryAsObject(conn, Long.class, sql, parameters);
	}

	protected static Float queryAsFloat(Connection conn, String sql,
			Object... parameters) {
		return queryAsObject(conn, Float.class, sql, parameters);
	}

	protected static String queryAsString(Connection conn, String sql,
			Object... parameters) {
		return queryAsObject(conn, String.class, sql, parameters);
	}

	protected Boolean queryAsBoolean(Connection conn, String sql,
			Object... parameters) {
		return queryAsObject(conn, Boolean.class, sql, parameters);
	}

	protected Date queryAsDate(Connection conn, String sql,
			Object... parameters) {
		return queryAsObject(conn, Date.class, sql, parameters);
	}

	@SuppressWarnings("unchecked")
	protected static Map<String, Object> queryAsMap(Connection conn, String sql,
			Object... parameters) {
		return queryAsObject(conn, Map.class, sql, parameters);
	}

	protected static <T> PageResult<T> queryAsPagelist(Connection conn,
			Class<T> beanClass, String sql, QueryCriteria queryCriteria) {
		PageResult<T> pr = new PageResult<T>();
		pr.setCurrentIndex(queryCriteria.getStartIndex());
		pr.setPageSize(queryCriteria.getPageSize());
		String countsql = SQLUtils.generateCountHql(sql, null);
		if (null != countsql) {// 获取总页数
			pr.setTotalCount(queryAsLong(conn, countsql,
					queryCriteria.getQueryCondition()));
		}
		if (0 != queryCriteria.getPageSize()) {
			pr.setTotalPage((int) ((pr.getTotalCount()
					+ queryCriteria.getPageSize() - 1) / queryCriteria
					.getPageSize()));
			pr.setCurrentPage((int) ((queryCriteria.getStartIndex() + queryCriteria
					.getPageSize()) / queryCriteria.getPageSize()));
		}
		if (queryCriteria.getStartIndex() > pr.getTotalPage()) {
			queryCriteria.setStartIndex(pr.getTotalPage());
		}
		sql = doGetDialet(conn).sql_pagelist(sql,
				queryCriteria.getStartIndex(), queryCriteria.getPageSize());

		pr.setContent(queryAsList(conn, beanClass, sql,
				queryCriteria.getQueryCondition()));
		return pr;
	}

	protected static <T> T query(Connection conn, ResultSetHandler<T> rsh, String sql,
			Object... parameters) {
		PreparedStatement ps = null;
		ResultSet rs = null;
		T result = null;
		try {
			ps = PreparedStatementCreator.createPreparedStatement(conn, sql,
					parameters);
			rs = ps.executeQuery();
			result = rsh.handle(rs);
		} catch (Throwable e) {
			throw SystemException.unchecked(e).set("sql", sql)
					.set("parameters", parameters);
		} finally {
			JdbcUtils.closeQuietly(rs);
			JdbcUtils.closeQuietly(ps);
		}
		return result;
	}

	protected static int execute(Connection conn, String sql, Object... parameters) {

		PreparedStatement ps = null;
		int rows = 0;

		try {
			ps = PreparedStatementCreator.createPreparedStatement(conn, sql,
					parameters);
			rows = ps.executeUpdate();
		} catch (Exception e) {
			throw SystemException.unchecked(e).set("sql", sql)
					.set("parameters", parameters);
		} finally {
			JdbcUtils.closeQuietly(ps);
		}

		return rows;
	}

	protected static int[] executeBatch(Connection conn, String sql,
			List<Object[]> parameters) {

		PreparedStatement ps = null;
		int[] rows;

		try {
			ps = conn.prepareStatement(sql);
			for (Object[] parameter : parameters) {
				for (int i = 0; i < parameter.length; i++) {
					ps.setObject(i + 1, parameter[i]);
				}
				ps.addBatch();
			}
			rows = ps.executeBatch();
		} catch (SQLException e) {
			throw SystemException.unchecked(e).set("sql", sql)
					.set("parameters", parameters);
		} finally {
			JdbcUtils.closeQuietly(ps);
		}

		return rows;
	}

	/**
	 * 判断表是否已经存在
	 */
	protected boolean tableExist(Connection conn, String name) {
		ResultSet rs = null;
		try {
			DatabaseMetaData metaData = conn.getMetaData();
			rs = metaData.getTables(null, null, name.toUpperCase(),
					new String[] { "TABLE" });
			return rs.next();
		} catch (SQLException e) {
			throw SystemException.unchecked(e);
		} finally {
			JdbcUtils.closeQuietly(rs);
			// closeConnection(conn);
		}
	}

	protected static Dialect doGetDialet(Connection conn) {
		try {
			String name = conn.getMetaData().getDatabaseProductName();
			return Dialect.getDialect(name);
		} catch (SQLException e) {
			throw SystemException.unchecked(e);
		}
	}

	@SuppressWarnings("unchecked")
	protected static <T> RowMapper<T> getRowMapper(Class<T> beanClass) {
		RowMapper<T> rowMapper;
		if (beanClass.isArray()) {
			rowMapper = (RowMapper<T>) new ArrayRowMapper();
		} else if (beanClass.getName().equals("java.util.Map")) {
			rowMapper = (RowMapper<T>) new MapRowMapper();
		} else if (beanClass.getName().startsWith("java.")) {
			rowMapper = new SingleColumnRowMapper<T>(beanClass);
		} else {
			rowMapper = new BeanRowMapper<T>(beanClass);
		}
		return rowMapper;
	}
}
